﻿#region Copyright information
// 
// Copyright © 2005-2013 Yongkee Cho. All rights reserved.
// 
// This code is a part of the Biological Object Library and governed under the terms of the
// GNU Lesser General  Public License (LGPL) version 2.1 which accompanies this distribution.
// For more information on the LGPL, please visit http://bol.codeplex.com/license.
// 
// - Filename: BinaryCardinality.cs
// - Author: Yongkee Cho
// - Email: yongkeecho@gmail.com
// - Date Created: 2012-09-06 11:39 AM
// - Last Modified: 2013-01-25 3:59 PM
// 
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using BOL.Collections;

namespace BOL.Linq.Distances
{
    public static partial class Similarity
    {
        /// <summary>
        /// Counts the number of possible cases of bit in two binary sequences.
        /// </summary>
        /// <param name="first">The first input sequence.</param>
        /// <param name="second">The second input sequence.</param>
        /// <returns>Returns the number of possible cases of bit being (1, 1), (1, 0), (0, 1) and (0, 0).</returns>
        public static Tuple<int, int, int, int> BinaryCardinality(this IEnumerable<bool> first, IEnumerable<bool> second)
        {
            var x = new BitArray(first.ToArray());
            var y = new BitArray(second.ToArray());
            var length = x.Length;
            if (length != y.Length)
                throw new ArgumentOutOfRangeException("first");

            var b = x.CountBits();
            var c = y.CountBits();
            var a = x.And(y).CountBits();
            b -= a;
            c -= a;
            var d = length - a;
            
            return new Tuple<int, int, int, int>(a, b, c, d);

            //// slower code
            //var count = new int[4];
            //var length = Math.Min(fl.Count, sl.Count);
            //for (var i = 0; i < length; i++)
            //    count[(fl[i] ? 2 : 0) + (sl[i] ? 1 : 0)]++; 
            //
            //return new Tuple<int, int, int, int>(count[3], count[2], count[1], count[0]);

            //// much slower code 
            // var a = first.Zip(second, (f, s) => (f ? 2 : 0) + (s ? 1 : 0)).ToList();
            // var count = Enumerable.Range(0, 4).Select(x => x.Count(a.Contains)).ToArray();
            //
            //return new Tuple<int, int, int, int>(count[3], count[2], count[1], count[0]);
        }

        public static int T1(Tuple<int, int, int, int> bc)
        {
            return Math.Max(bc.Item1, bc.Item2) + Math.Max(bc.Item3, bc.Item4) + Math.Max(bc.Item1, bc.Item3) + Math.Max(bc.Item2, bc.Item4);
        }

        public static int T2(Tuple<int, int, int, int> bc)
        {
            return Math.Max(bc.Item1 + bc.Item2, bc.Item2 + bc.Item4) + Math.Max(bc.Item1 + bc.Item2, bc.Item3 + bc.Item4);
        }

        public static int Total(Tuple<int, int, int, int> bc)
        {
            return bc.Item1 + bc.Item2 + bc.Item3 + bc.Item4;
        }
    }
}
